﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using StyleMVVM.Logging;

namespace StyleMVVM.DependencyInjection
{
	/// <summary>
	/// DisposalScope holds a set of objects waiting to be disposed when the disposal scope is disposed
	/// </summary>
	public sealed class DisposalScope : IDisposalScope
	{
		private List<Tuple<IDisposable, BeforeDisposalCleanupDelegate>> disposalList = 
			new List<Tuple<IDisposable, BeforeDisposalCleanupDelegate>>();

		/// <summary>
		/// Key to be used to lookup disposal scope
		/// </summary>
		public static string DisposalScopeStringKey
		{
			get { return "DisposalScope"; }
		}

		public void Dispose()
		{
			Dispose(true);
		}

		private void Dispose(bool dispose)
		{
			if(dispose)
			{
				if (disposalList != null)
				{
					foreach (Tuple<IDisposable, BeforeDisposalCleanupDelegate> disposableTuple in disposalList)
					{
						if (disposableTuple.Item2 != null)
						{
							try
							{
								disposableTuple.Item2(disposableTuple.Item1);
							}
							catch (Exception exp)
							{
								Logger.Error("Exception thrown while calling clean up method for disposed type " + disposableTuple.Item1.GetType(),
									typeof(DisposalScope).FullName, exp);
							}
						}

						try
						{
							disposableTuple.Item1.Dispose();
						}
						catch (Exception exp)
						{
							Logger.Error("Exception thrown while disposing object", typeof(DisposalScope).FullName, exp);
						}
					}

					disposalList = null;
				}
			}
		}

		public void AddObject(IDisposable newObject)
		{
			disposalList.Add(new Tuple<IDisposable, BeforeDisposalCleanupDelegate>(newObject,null));
		}

		public void AddObject(IDisposable newObject, BeforeDisposalCleanupDelegate cleanupDelegate)
		{
			disposalList.Add(new Tuple<IDisposable, BeforeDisposalCleanupDelegate>(newObject, cleanupDelegate));
		}
	}
}
